<?php
namespace App\Http\Controllers\Manage;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Validator;
use PRedis;
use Form;
use App\Ext\Common\UploadImage;use App\Model\ManageRole;
use App\Model\ManageMapRole;
use App\Model\ManageAction;
use App\Model\ManageRoleMapAction;

class CommonController extends Controller
{
    protected $request;
    protected $user;
    protected $domain;
    protected $path; # 公共上传文件路径
    protected $filePath; # 公共文件路径

    function __construct(Request $request)
    {
        $this->request = $request;
        $uid = $request->session()->get('manage');
        $this->user = PRedis::HGetAll('manage:' . $uid);
        # 管理台视图全局数据
        if (!$this->user) {
            return redirect()->route('manage:login');
        }
        $this->domain = env('APP_URL', '/');
        view()->share('username', $this->user['username']);
        view()->share('skin', 'blue-green');
        view()->share('domain', $this->domain);
        view()->share('manage_title', trans('manage.title'));
        view()->share('manage_welcome',trans('manage.welcome_title'));
        $this->path = path();
        $this->filePath = filePath();
    }

    /**
     * 获取用户拥有的角色
     * @param $uid
     * @return array
     */
    protected function getRole($uid)
    {
        $role = array();
        $result = ManageMapRole::where('manage_id', $uid)->get();
        foreach ($result as $val) {
            $role[] = $val->role_id;
        }
        return $role;
    }

    /**
     * 验证用户拥有的角色权限
     * @param $role
     * @param $code
     * @return bool
     */
    protected function checkRule($role, $code)
    {
        if (is_string($role)) {
            $role = explode(',', $role);
        }
        $rule = $this->getRoleRule($role);
        if (array_search($code, $rule)) {
            return true;
        }
        return false;
    }

    /**
     *
     * 获取角色的权限数据
     *
     * @param $roles
     * @return array
     */
    private function getRoleRule($roles)
    {
        $actions = array(); # 角色授权信息
        foreach ($roles as $val) {
            # 检查Redis中缓存的角色信息
            $result = PRedis::HGet('manage:role', $val);
            if ($result) {
                $result = unserialize($result);
                $actions = array_merge($actions, $result['action']);
            } else {
                # 保存没有缓存到Redis的角色ID
                $result = $this->saveRoleRule($val);
                if ($result) $actions = array_merge($actions, $result);
            }
        }
        return array_unique($actions);
    }

    /**
     *
     * 查询角色权限并且缓存角色数据到Redis
     *
     * @param $id
     * @return bool|array
     */
    private function saveRoleRule($id)
    {
        # 查询角色信息
        $role = ManageRole::find($id);
        # 查询角色关联的权限ID
        $actionID = ManageRoleMapAction::where('role_id', $id)->lists('action_id')->toArray();
        # 查询权限码
        $actionCode = ManageAction::whereIn('id', $actionID)->lists('action_code')->toArray();
        if ($actionCode) {
            # 缓存权限到redis
            $data = serialize([
                'name' => $role->name,
                'action' => $actionCode,
            ]);
            PRedis::Hset('manage:role', $id, $data);
            return $actionCode;
        }
        return false;
    }

    /**
     *
     * 载入标签导航栏
     *
     * @param $name
     * @param $active
     * @param null $param
     * @return array
     */
    protected function navTab($name, $active, $param = null)
    {
        $value = array();
        $value['name'] = 'manage.lib.nav.' . $name;
        $value['active'] = $active;
        return ($param != null) ? $value + $param : $value;
    }

    /**
     *
     * ORM模型的约束查询封装
     * 使用客户端浏览器的cookie传递查询约束条件
     * 返回paginate方法的查询结果集
     *
     * @param $db ORM模型对象
     * @param $field 查询字段
     * @param $range 关键词替换参数
     * @return mixed ORM模型方法的结果集
     */
    protected function constraintSelect($db, $field, $range = null)
    {
        $db = $db->select(array_keys($field));
        $search = $this->getCookieSearch();
        if ($search && isset($field[$search->field])) {
            $keyword = $search->keyword;
            if (isset($range[$search->field])) {
                $keyword = array_search($search->keyword, $range[$search->field]);
            }
            $db = $db->where($search->field, $search->condition, $keyword);
        }
        $sort = $this->getCookieSort();
        if ($sort && isset($field[$sort->field])) {
            $db = $db->orderBy($sort->field, $sort->value);
        }
        $limit = $this->getCookieLimit();
        $db = $db->paginate($limit);
        return $db;
    }

    /**
     *
     * ORM模型的约束查询封装
     * 使用客户端浏览器的cookie传递查询约束条件
     * 返回paginate方法的查询结果集
     *
     * @param $db ORM模型对象
     * @param $field 查询字段
     * @param $range 关键词替换参数
     * @return mixed ORM模型方法的结果集
     */
    protected function constraintSelectDB($db, $range = null)
    {
        $search = $this->getCookieSearch();
        if ($search && isset($field[$search->field])) {
            $keyword = $search->keyword;
            if (isset($range[$search->field])) {
                $keyword = array_search($search->keyword, $range[$search->field]);
            }
            $db = $db->where($search->field, $search->condition, $keyword);
        }
        $sort = $this->getCookieSort();
        if ($sort && isset($field[$sort->field])) {
            $db = $db->orderBy($sort->field, $sort->value);
        }
        $limit = $this->getCookieLimit();
        $db = $db->paginate($limit);
        return $db;
    }

    /**
     * 获取列表的条件查询限制
     */
    protected function getCookieSearch()
    {
        if (isset($_COOKIE['search'])) {
            $search = json_decode($_COOKIE['search']);
            if (!empty($search->field) && !empty($search->keyword)) {
                $search->condition = empty($search->condition) ? 1 : $search->condition;
                $search->condition = condition($search->condition);
                return $search;
            }
        }
        return false;
    }

    protected function getCookieLimit()
    {
        if (isset($_COOKIE['limit'])) {
            $limit = $_COOKIE['limit'];
            if (is_numeric($limit) && $limit > 0 && $limit <= 100) return $limit;
        }
        return 10;
    }

    protected function getCookieSort()
    {
        if (isset($_COOKIE['sort'])) {
            $sort = json_decode($_COOKIE['sort']);
            if (!empty($sort->field) && !empty($sort->value)) return $sort;
        }
        return false;
    }

    protected function uploadImage($file, $path)
    {
        $response = array();
        # 原始文件名
        $originalName = $file->getClientOriginalName();
        # 新文件名
        $fileName = time() . substr(mt_rand(), 5);
        $fileName = $fileName . '.' . $file->getClientOriginalExtension();
        # 验证图片大小
        $sizeMax = formatBytes($file->getMaxFilesize());
        $sizeMax = floor($sizeMax);
        $fileSize = formatBytes($file->getClientSize());
        if ($fileSize > $sizeMax) {
            $response['error'] = '文件"' . $originalName . '"容量为' . $fileSize . 'MB，超过上传文件大小限制，文件上传的最大限制为' . $sizeMax . 'MB';
            return $response;
        }
        $image = new UploadImage();
        # 验证图片格式
        $mime = ['jpg','jpeg','png']; # 文件类型限制
        if (!$image->checkMime($file, $mime)) {
            $response['error'] = '上传的文件格式限制为"jpg,jpeg,png"';
            return $response;
        }
        # 保存文件对象
        $result = $image->save($file, $this->path[$path], $fileName);
        # 上传到云存储
        # 返回保存文件信息
        if ($result) {
            $response['file'] = [
                'name' => $fileName,
                'original' => $originalName
            ];
            return $response;
        }
        $response['error'] = '文件上传失败';
        return $response;
    }

    protected function uploadBase64Image($base64, $path)
    {
        $fileName = time() . substr(mt_rand(), 5);
        return base64Image($base64, $fileName, $this->path[$path]);
    }

    /**
     *
     * 表单自动生成
     *
     * @param $params
     * @return array
     */
    protected function form($params)
    {
        $element = [];
        $ext = [];
        foreach ($params as $key => $param) {
            # 控件类型
            $type = $param['type'];
            # 引用控件扩展模板文件
            if (!isset($ext[$type])) {
                $result = $this->includeFormExt($type);
                if ($result) $ext[$type] = $result;
            }
            # 如果默认值为空或不存在默认为空
            if (!isset($param['value'])) $param['value'] = null;
            # 控件参数
            $element[$key] = [
                'col' => isset($param['col']) ? $param['col'] : '',
                'name' => isset($param['name']) ? $param['name'] : '',
                'type' => $type,
                'value' => $param['value']
            ];
            # 控件元素
            switch ($type) {
                case  'label':
                    $element[$key]['element'] = Form::label($key, $param['value'], ['class' => 'form-control']);
                    break;
                case 'text':
                    $element[$key]['element'] = Form::text($key, $param['value'], array('class' => 'form-control'));
                    break;
                case 'number':
                    $attr = [];
                    $attr['class'] = 'form-control';
                    if (isset($param['min']) && is_numeric($param['min'])) $attr['min'] = $param['min'];
                    if (isset($param['max']) && is_numeric($param['max'])) $attr['max'] = $param['max'];
                    $element[$key]['element'] = Form::number($key, $param['value'], $attr);
                    break;
                case 'date':
                    $element[$key]['element'] = Form::text($key, $param['value'], array('class' => 'form-control datepicker'));
                    break;
                case 'password':
                    $element[$key]['element'] = Form::password($key, array('class' => 'form-control'));
                    break;
                case 'textarea':
                    $element[$key]['element'] = Form::textarea($key, $param['value'], array('class' => 'form-control'));
                    break;
                case 'checkbox':
                    if (isset($param['range'])) {
                        $arr = array();
                        $param['value'] = explode(',', $param['value']);
                        foreach ($param['range'] as $k => $v) {
                            $checked = in_array($k, $param['value']) ? true : false;
                            $arr[] = array(
                                'name' => $v,
                                'input' => Form::checkbox($key.'[]', $k, $checked),
                            );
                        }
                        $element[$key]['element'] = $arr;
                    } else {
                        $element[$key]['element'] = Form::checkbox($key, $param['value']);
                    }
                    break;
                case 'checkbox-group':
                    # 生成复选框组控件
                    if (isset($param['range'])) {
                        $element[$key]['element'] = $this->checkboxGroup($key, $param['value'], $param['range']);
                    }
                    break;
                case 'checkbox-tree':
                    # 生成复选框组控件
                    if (isset($param['range'])) {
                        $element[$key]['element'] = $param['range'];
                        /*
                        $arr = array();
                        foreach ($param['range'] as $k => $v) {
                            $checked = in_array($v['id'], $param['value']) ? true : false;
                            $arr[] = array(
                                'name' => $v['name'],
                                'input' => Form::checkbox($key.'[]', $v['id'], $checked),
                                'br' => '<br/>'
                            );
                            if(isset($v['child'])){
                                foreach ($v['child'] as $kk => $vv) {
                                    $checked = in_array($vv['id'], $param['value']) ? true : false;
                                    $arr[] = array(
                                        'name' => $vv['name'],
                                        'input' => Form::checkbox($key.'[]', $vv['id'], $checked),
                                        'br' =>  '<br/>|--'
                                    );
                                    if(isset($vv['child'])){
                                        foreach ($vv['child'] as $kkk => $vvv) {
                                            $checked = in_array($vvv['id'], $param['value']) ? true : false;
                                            $arr[] = array(
                                                'name' => $vvv['name'],
                                                'input' => Form::checkbox($key.'[]', $vvv['id'], $checked),
                                                'br' => ($kkk == 0) ? '<br/>|----' : ''
                                            );
                                        }
                                    }
                                }
                            }
                        }
                        $element[$key]['element'] = $arr;
                        */
                    }
                    break;
                case 'radio':
                    if (isset($param['range'])) {
                        $arr = array();
                        foreach ($param['range'] as $k => $v) {
                            $checked = $param['value'] == $k ? true : false;
                            $arr[] = array(
                                'name' => $v,
                                'input' => Form::radio($key, $k, $checked),
                            );
                        }
                        $element[$key]['element'] = $arr;
                    } else {
                        $element[$key]['element'] = Form::radio($key, $param['value']);
                    }
                    break;
                case 'select':
                    if (isset($param['default'])) {
                        if (strstr($param['default'], ':')) {
                            # 拆分字符串为数组
                            $temp = explode(':', $param['default']);
                            $default = [$temp[0] => $temp[1]];
                        } else {
                            $default = [$param['default'] => '请选择'];
                        }
                        $range = (!empty($param['range'])) ? $param['range'] : [];
                        $param['range'] = $default + $range;
                    }
                    $element[$key]['element'] = Form::select($key, $param['range'], $param['value'], ['class' => 'form-control']);
                    break;
                case 'relation-select':
                    $attrParam = [];
                    $attrParam['id'] = $key;
                    $attrParam['url'] = $param['range'];
                    $attrParam['class'] = 'form-control relation-select';
                    if ($param['value']) $attrParam['data'] = $param['value'];
                    $element[$key]['element'] = Form::select($key, [], null, $attrParam);
                    break;
                case 'thumb':
                    $element[$key]['element'] = $this->thumb($key, $param['value'], $param['ratio']);
                    break;
                case 'file';
                    # 上传文件格式限定
                    $accept = isset($param['accept']) ? $param['accept'] : null;
                    # 上传文件大小限定
                    $maxSize = (isset($param['max_size']) && is_numeric($param['max_size'])) ? $param['max_size'] : null;
                    # 文件异步上传接口
                    $upload = isset($param['upload']) ? $param['upload'] : null;
                    # 生成文件上传控件
                    $element[$key]['element'] = $this->inputFile($key, $param['value'], $accept, $maxSize);
                    break;
                case 'multiFile';
                    # 上传文件格式限定
                    $accept = isset($param['accept']) ? $param['accept'] : null;
                    # 上传文件大小限定
                    $maxSize = (isset($param['max_size']) && is_numeric($param['max_size'])) ? $param['max_size'] : null;
                    # 上传文件最多数量限定
                    $maxCount = (isset($param['max_count']) && is_numeric($param['max_count'])) ? $param['max_count'] : null;
                    # 文件异步上传接口
                    $upload = isset($param['upload']) ? $param['upload'] : null;
                    # 生成文件上传控件
                    $element[$key]['element'] = $this->inputFile($key, $param['value'], $accept, $maxSize, $maxCount, $upload);
                    break;
                case 'editor':
                    $uploadImage = isset($param['upload_image']) ? $param['upload_image'] : null;
                    $element[$key]['element'] = Form::textarea($key, $param['value'], ['class'=>'summernote', 'upload-image' => $uploadImage]);
                    break;
                case 'distpicker':
                    $element[$key]['element'] = Form::text($key, $param['value'], ['class' => 'distpicker']);
                    break;
                case 'datetimepicker':
                    $element[$key]['element'] = Form::text($key, $param['value'], array('class' => 'form-control datetimepicker'));
                    break;

            }
        }
        return [
            'element' => $element,
            'ext' => $ext
        ];
    }

    /**
     *
     * 载入表单控件
     *
     * @param $name
     * @return array|mixed
     */
    private function includeFormExt($name)
    {
        $path = [
            'date' => 'manage.lib.form.datepicker',
            'file' => 'manage.lib.form.fileinput',
            'multiFile' => 'manage.lib.form.fileinput',
            'editor' => 'manage.lib.form.summernote',
            'thumb' => 'manage.lib.form.cropper_picture',
            'distpicker' => 'manage.lib.form.distpicker',
            'datetimepicker' => 'manage.lib.form.datetimepicker',
            'relation-select' => 'manage.lib.form.relation_select',
            'checkbox-tree' => 'manage.lib.form.checkbox_tree'
        ];
        return isset($path[$name]) ? $path[$name] : false;
    }

    private function thumb($name, $value, $ratio = null)
    {
        $ratio = $ratio != null ? $ratio : null;
        if (empty($value)) $value = '/asset/test.jpg';
        $element = Form::textarea($name, null, [
            'class' => 'cropper-image hide',
            'data-ratio' => $ratio,
            'data-src' => $value,
        ]);
        return $element;
    }

    private function checkboxGroup($name, $value, $range)
    {
        $groups = array();
        foreach ($range as $group) {
            $child = array();
            if (isset($group['child'])) {
                foreach ($group['child'] as $val) {
                    $checked = false;
                    if (!empty($value[$group['value']])) {
                        if (in_array($val['value'], $value[$group['value']])) $checked = true;
                    }
                    $child[] = array(
                        'name' => $val['name'],
                        'input' => Form::checkbox($name.'[' . $group['value'] . '][]', $val['value'], $checked),
                    );
                }
            }
            $groups[] = [
                'name' => $group['name'],
                'value' => $group['value'],
                'child' => $child,
            ];
        }
        return $groups;
    }

    private function inputFile($name, $value, $accept, $maxSize, $maxCount = 1, $upload = null)
    {
        $param = [
            'class' => 'fileinput file-loading',
            'data' => $value,
            'max_size' => $maxSize,
        ];
        # 定义文件类型限定的文件扩展名
        $ext = [
            'image' => 'jpg,jpeg,png,gif,bmp',
            'doc' => 'text,txt,doc,cvs,xls',
            'video' => 'mp4,avi',
        ];
        if (isset($ext[$accept])) {
            $param['accept'] = $ext[$accept];
        }
        # 定义多选文件限定
        if ($maxCount > 1) {
            $param['max-count'] = $maxCount;
            $param['multiple'] = 'multiple';
        }
        # 定义文件接口
        if ($upload != null) {
            $param['upload'] = $upload;
        }
        return Form::file($name, $param);
    }

    /**
     *
     * 验证接口访问者身份old (LotteryProductPictureController, EditorController)
     *
     * @param $token
     * @return bool
     */
    protected function authGuest($token)
    {
        if ($token) {
            $this->user = PRedis::HGetAll('token:' . $token);
            if ($this->user) return true;
        }
        //abort(403, 'You have no access!');
        return false;
    }
}
